/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.kiakaku.downloadpage;

import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.htmlparser.jericho.*;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.SimpleDirectedGraph;
import org.kiakaku.utility.FileUtility;

/*
 *   File OutLink is created by kiakaku on Mar 2, 2012 1:24:57 PM
 * If you want modify this file please insert information in here 
 * - Last modify in Mar 2, 2012, 1:24:57 PM by kiakaku
 *                  
 *
 * @author kiakaku
 */
public class OutLink {

    public static final String ROOT = "http://dantri.com.vn/c26/thethao.htm";
    //Nhãn không phải thể thao:  phap luat, giai tri, giao duc, xa hoi, the gioi, suc khoe, suc manh so, KINH DOANH, oto xe máy, tam long nhan ai
    public static final String SOURCE_FILE = "source_id.txt";
    public static final String TAGET_FILE = "target_id.txt";
    public static final String ALL_NODE = "list_all_node.txt";
    public static final int MAX_PAGE = 50000;
    public static final String SVM_FILE_MODEL = "svm//model.txt.model";
    public static final String SVM_FILE_RESULT = "svm//result.txt";
    SimpleDirectedGraph<Node, DefaultEdge> graph;
    private static int numberOfPage = 0; // so luong url da xet
    Queue<Node> queue;
    List<String> allQueue;
    int id;
//    ChuanHoaFileHuanLuyen chuanHoa;
    MyLogger log;
//    tokenfile tokenizer;
    int count = 0;

    public OutLink() {
        log = new MyLogger();
        allQueue = new LinkedList();
//        tokenizer = new tokenfile();
        id = 1;
        graph = new SimpleDirectedGraph<Node, DefaultEdge>(DefaultEdge.class);
        queue = new LinkedList<Node>();
//        chuanHoa = new ChuanHoaFileHuanLuyen();
//        chuanHoa.docTuDienTuFile(); // khởi tạo từ điển cho lớp ChuanHoaFileHuanLuyen cả từ điển word và từ điển String
//        System.out.println("từ điển");
//        System.out.println(chuanHoa.dict.toString());
//        System.out.println(chuanHoa.wordString.toString());
//        MicrosoftConditionalCommentTagTypes.register();
//        PHPTagTypes.register();
//        PHPTagTypes.PHP_SHORT.deregister(); // remove PHP short tags for this example otherwise they override processing instructions
//        MasonTagTypes.register();
    }

    /*
     * Hàm lấy ra tất cả các link chưa trong trang web mà có url là tham số đầu vào
     * Và chú ý là chỉ lấy các phần tử nằm trong element <div class="wrapper"> </div>
     * Paramater : url (String) url của trang web cần lấy outlink
     * return : List<String> danh sách địa chỉ các trang chứa trong trang url
     */
    public List<Node> getOutNode(Node currNode) {
        List<Node> outlink = new LinkedList<Node>();
        try {
            System.out.println("New source " + count + " (trang:" + numberOfPage + ")" + currNode.getUrl() + "\tdept" + currNode.getDepth());
            count++;
            Source source = new Source(new URL(currNode.getUrl()));
            System.out.println("Xong new source");
            source.setLogger(null);
            List<Element> div = source.getAllElements(HTMLElementName.DIV);
            // download site
            Element chi_tiet = null;
            for (Element temp : div) {
                if ("ctl00_IDContent_Tin_Chi_Tiet".equalsIgnoreCase(temp.getAttributeValue("id"))) {
                    chi_tiet = temp;
                    break;
                }
            }
            if (chi_tiet == null) {
                for (Element temp : div) {
                    if ("container".equalsIgnoreCase(temp.getAttributeValue("class"))) {
                        chi_tiet = temp;
                        break;
                    }
                }
            }
            if (chi_tiet == null) {
                for (Element temp : div) {
                    if ("detail".equalsIgnoreCase(temp.getAttributeValue("class"))) {
                        chi_tiet = temp;
                        break;
                    }
                }
            }
            if (chi_tiet == null) {
                for (Element temp : div) {
                    if ("homehighlight-left".equalsIgnoreCase(temp.getAttributeValue("class"))) {
                        chi_tiet = temp;
                        break;
                    }
                }
            }
            if (chi_tiet == null) {
                chi_tiet = div.get(0);
            }
            TextExtractor txtExtract = new TextExtractor(chi_tiet) {

                @Override
                public boolean excludeElement(StartTag st) {
                    if (st.getName().equalsIgnoreCase(HTMLElementName.DIV) && "list-video-header".equalsIgnoreCase(st.getAttributeValue("class"))) {
                        return true;
                    }
                    return false;
                }
            };
            FileUtility.ghiFile(txtExtract.toString(), "data\\" + currNode.hashCode() + ".txt");
            // tìm outlink
            Element wrapper = null;
            Element subnav = null;
            System.out.println("Tìm wapper");
            for (Element temp : div) {
                if ("subnav".equalsIgnoreCase(temp.getAttributeValue("class"))) {
                    subnav = temp;
                }
                if ("wrapper".equalsIgnoreCase(temp.getAttributeValue("class"))) {
                    wrapper = temp;
                }
            }
            if (wrapper == null) {
                for (Element temp : div) {
                    if ("wrap".equalsIgnoreCase(temp.getAttributeValue("id"))) {
                        wrapper = temp;
                    }
                }
            }
            if (wrapper != null) {
                List<Element> linkElements = wrapper.getAllElements(HTMLElementName.A);
                if (subnav != null) {
                    linkElements.addAll(subnav.getAllElements(HTMLElementName.A));
                }
                for (Element linkElement : linkElements) {
                    String href = linkElement.getAttributeValue("href");
                    if (!(href.contains("/c26"))) { // the thao
                        if (!(href.contains("seagames"))) {
                            if (!(href.contains("/c404/"))) {
                                if (!(href.contains("/c741/"))) { //
                                    continue;
                                }
                            }
                        }
                    }
                    if (href == null
                            || href.length() == 1
                            || (!(".htm".equalsIgnoreCase(href.substring(href.length() - 4))))
                            || href.contains("javascript")
                            || href.indexOf('?') != -1
                            || href.indexOf('#') != -1) {
                        continue;
                    }
                    if (getMainURL(href) == null) { // nếu đây là địa chỉ tương đối
                        if (href.charAt(0) != '/') {
                            href = getMainURL(currNode.getUrl()) + "/" + href;
                        }
                        href = getMainURL(currNode.getUrl()) + href;
                    }
                    if (href.contains("http://m.") || href.contains("https://m.") // loại bỏ các trang cho điện thoại di động

                            || href.equalsIgnoreCase(currNode.getUrl())
                            || currNode.getUrl().equalsIgnoreCase(href.substring(0, href.length() - 1))) { // Nếu trùng với url đầu vào thì bỏ qua
                        continue;
                    }
                    // Thêm phần node đã có trong đồ thì thì dept của nó là dept của node trong đồ thị
                    if (!(outlink.contains(new Node(href, -1, -1)))) {
                        if (href.contains("dantri.com.vn")) {
                            List<Node> a = new LinkedList<Node>(graph.vertexSet());
                            int b = a.indexOf(new Node(href, -1, -1));
                            if (b > 0) {
                                outlink.add(a.get(b));
                            } else {
                                outlink.add(new Node(href, currNode.getDepth() + 1, -1)); // rang của node được tăng lên một
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(OutLink.class.getName()).log(Level.SEVERE, null, ex);
        }
        return outlink;
    }
    /*
     * Hàm để add một tập các phần tử vào trong queue
     * Chỉ add các phần từ mà chưa từng xuất hiện trong queue
     */

    public void addListToQueue(Queue<String> a, List<Node> b) {
        System.out.println("add queue");
        for (int i = 0; i < b.size(); i++) {
            if (!(allQueue.contains(b.get(i).getUrl()))) {
                a.offer(b.get(i).getUrl());
                allQueue.add(b.get(i).getUrl());
            }
        }
    }
    /*
     * Duyệt theo chiều rộng để xấy dựng được đồ thị có hướng
     * Sau đó đồ thị được lưu vào file 
     */

    public void breadthFirstSearch(String root) {
        numberOfPage = 0;
        // khai báo tránh vòng lặp
        List<Node> temp = new LinkedList<Node>();
        Node curr = new Node(root, 0, 0);
        queue.offer(curr);
        allQueue.add(curr.getUrl());
        curr.setId(numberOfPage);
        graph.addVertex(curr);
        numberOfPage++;
        Node next = null;
        while (!queue.isEmpty() && numberOfPage <= MAX_PAGE) { // duyệt theo chiều rộng đến khi đạt được số lượng web là MAX_PAGE
            curr = queue.poll();
            System.out.println("get out node");
            temp = getOutNode(curr);
            System.out.println("Add list to queue");
//            addListToQueue(queue, temp);// push toàn bộ node kề với node curr 
            int soTrangConCoIch = 0;
            for (int i = 0; i < temp.size(); i++) { // Với mỗi đỉnh next kề với node curr
                if (numberOfPage > MAX_PAGE) {
                    break;
                }
                next = temp.get(i);
                if (!(graph.containsVertex(next))) {
                    next.setId(numberOfPage);
                    graph.addVertex(next);
                    System.out.println(next.getUrl() + "\t\t\t\tTrang số :" + numberOfPage + "\t\t" + "dept:" + next.getDepth());
                    numberOfPage++;
                    graph.addEdge(curr, next);
                    soTrangConCoIch++;
                    if (!(queue.contains(next))) {
                        queue.add(next);
                    } else {
                        System.out.println("Có rồi");
                    }
                } else { // trong đồ thì đã có node next
//                    queue.remove(next);
                    if (curr.getDepth() <= next.getDepth()) {
                        System.out.println("Liên kết khác:" + curr.getDepth() + "->" + next.getDepth());
                        graph.addEdge(curr, next);
                    }
                }
            }
//            if(soTrangConCoIch <2){
//                queue.remove();
//            }
        }
        //ghi thông tin đồ thị
        List<Integer> source_id = new LinkedList<Integer>();
        List<Integer> target_id = new LinkedList<Integer>();
        List<Node> all = new LinkedList<Node>(graph.vertexSet());
        List<DefaultEdge> edgeList = new LinkedList<DefaultEdge>(graph.edgeSet());
        for (DefaultEdge defaultEdge : edgeList) {
            source_id.add(graph.getEdgeSource(defaultEdge).getId());
            target_id.add(graph.getEdgeTarget(defaultEdge).getId());
        }
        FileUtility.ghiListOne(all, ALL_NODE);
        FileUtility.ghiListInt(source_id, SOURCE_FILE);
        FileUtility.ghiListInt(target_id, TAGET_FILE);
    }


    /*
     * Hàm để lấy tên miền của trang web hiện tài
     * Ví dụ : http://dantri.com.vn/c20/s20-570788/ha-noi-xe-lexus-bac-ty-bat-ngo-boc-chay.htm
     * thì kết quả trả về sẽ là http://dantri.com.vn
     * Nếu url hiện tại ko có tên miền chính
     * Ví dụ : /c20/s20-570788/ha-noi-xe-lexus-bac-ty-bat-ngo-boc-chay.htm
     * Thì kết quả trả về null
     * 
     * Hàm đã test chuẩn
     * Kiakaku
     */
    public String getMainURL(String url) {
        if (url.length() < 7) {
            return null;
        } else {
            if ("http://".equalsIgnoreCase(url.substring(0, 7))) {
                int pos = url.substring(7).indexOf('/');
                if (pos == -1) {
                    return url;
                }
                return url.substring(0, 7 + pos);
            }
        }
        return null;
    }

    public void downloadOneSite(Node site) {
        try {
            Source source = new Source(new URL(site.getUrl()));
            source.setLogger(null);
            List<Element> div = source.getAllElements(HTMLElementName.DIV);
            Element chi_tiet = null;
            for (Element temp : div) {
                if ("ctl00_IDContent_Tin_Chi_Tiet".equalsIgnoreCase(temp.getAttributeValue("id"))) {
                    chi_tiet = temp;
                    break;
                }
            }
            if (chi_tiet == null) {
                for (Element temp : div) {
                    if ("container".equalsIgnoreCase(temp.getAttributeValue("class"))) {
                        chi_tiet = temp;
                        break;
                    }
                }
            }
            TextExtractor txtExtract = new TextExtractor(chi_tiet) {

                @Override
                public boolean excludeElement(StartTag st) {
                    if (st.getName().equalsIgnoreCase(HTMLElementName.DIV) && "list-video-header".equalsIgnoreCase(st.getAttributeValue("class"))) {
                        return true;
                    }
                    return false;
                }
            };
            FileUtility.ghiFile(txtExtract.toString(), "data\\" + site.getId() + ".txt");
            txtExtract = null;
        } catch (IOException ex) {
            Logger.getLogger(OutLink.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

//    public String tachTu(String pathFile) {
//        System.out.println("Start tach tu ");
//        String result = null;
//        List<String> tu = new ArrayList<String>();
//        tokenizer.tokenizeio(pathFile, "temp\\output.temp.txt");
//        result = FileUtility.docFile("temp\\output.temp.txt");
//        result = result.toLowerCase();
//        int soLanXuatHien[] = new int[result.length()];
//        String temp = null;
//        result = result.replace("\n", " ");
//        int firstIndex = 0;
//        for (int i = 0; i < result.length(); i++) {
//            if (result.charAt(i) == ' ') {
//                temp = result.substring(firstIndex, i);
//                temp = temp.replace('_', ' ');
//                if (!tu.contains(temp)) {
//                    tu.add(temp);
//                }
//                soLanXuatHien[tu.indexOf(temp)]++;
//                firstIndex = i + 1;
//            }
//        }
//        StringBuilder te = new StringBuilder();
//        String a = null;
//        for (int i = 0; i < tu.size(); i++) {
//            a = "" + soLanXuatHien[i];
//            te.append(tu.get(i)).append("\t").append(a).append("\n");
//        }
//        System.out.println("finnish tach tu");
//        return te.toString();
//    }
    public static void main(String[] args) {
        OutLink a = new OutLink();
        System.out.println("Start at: " + new Date().toString());
        a.breadthFirstSearch(ROOT);
        System.out.println("Kích thước đồ thị :" + a.graph.vertexSet().size());
    }
}
